package mspbots.cw.business.core.timeentry;

import com.fasterxml.jackson.databind.JsonNode;
import lombok.RequiredArgsConstructor;
import lombok.extern.log4j.Log4j2;
import mspbots.cw.business.core.BaseReceiver;
import mspbots.cw.business.core.tickets.SysDictDataEntity;
import mspbots.cw.business.core.tickets.TicketsRepository;
import mspbots.cw.business.core.users.UsersRepository;
import mspbots.cw.common.ResultMsg;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.data.relational.core.query.Criteria;
import org.springframework.data.relational.core.query.Query;
import org.springframework.stereotype.Component;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;

import java.time.Duration;
import java.time.LocalDateTime;

/**
 * @author Jay.Yang
 */
@Log4j2
@Component
@RequiredArgsConstructor
public class TimeEntriesReceiver extends BaseReceiver {

    private final TimeEntriesRepository timeEntriesRepository;
    private final TicketsRepository ticketsRepository;
    private final UsersRepository usersRepository;

    @RabbitListener(queues = "connect-wise.time-entries.tl")
    public void process(ResultMsg resultMsg) {
        JsonNode entity = resultMsg.getEntity();
        TimeEntry data = TimeEntry.builder()
                .timeentryId(resultMsg.getId())
                .action("added")
                .actualHours(super.getDoubleValue(entity.get("actualHours")))
                .addToResolutionFlag(super.getBooleanValue(entity.get("addToResolutionFlag")))
                .addToDetailDescriptionFlag(super.getBooleanValue(entity.get("addToDetailDescriptionFlag")))
                .billableOption(super.getStringValue(entity.get("billableOption")))
                .chargeToType(super.getStringValue(entity.get("chargeToType")))
                .companyId(super.getLongValueId(entity.get("company")))
                .companyName(super.getStringValueName(entity.get("company")))
                .cwUid(super.getLongValueId(entity.get("member")))
                .dateEntered(super.getDateTimeValue(entity.findValue("dateEntered")))
                .internalNotes(super.getStringValue(entity.get("internalNotes")))
                .notes(super.getStringValue(entity.get("notes")))
                .status(super.getStringValue(entity.get("status")))
                .syncTime(LocalDateTime.now())
                .ticketId(super.getLongValue(entity.get("chargeToId")))
                .timeEnd(super.getDateTimeValue(entity.get("timeEnd")))
                .timeStart(super.getDateTimeValue(entity.get("timeStart")))
                .updateTime(super.getDateTimeValue(entity.findValue("lastUpdated")))
                .workTypeName(super.getStringValueName(entity.get("workType")))
                .memberId(super.getLongValueId(entity.get("member")))
                .memberName(super.getStringValueName(entity.get("member")))
                .locationId(super.getLongValue(entity.get("locationId")))
                .hourlyRate(super.getDoubleValue(entity.get("hourlyRate")))
                .workRoleId(super.getLongValueId(entity.get("workRole")))
                .workRoleName(super.getStringValueName(entity.get("workRole")))
                .updatedBy(ObjectUtils.isEmpty(entity.get("_info")) ? null : super.getStringValue(entity.get("_info").get("updatedBy")))
                .hasAgreement(!ObjectUtils.isEmpty(entity.get("agreement")))
                .agreementId(super.getLongValueId(entity.get("agreement")))
                .agreementName(super.getStringValueName(entity.get("agreement")))
                .agreementAmount(super.getDoubleValue(entity.get("agreementAmount")))
                .consumeTime(LocalDateTime.now())
                .build();
        data.setNotes(StringUtils.isEmpty(data.getNotes()) ? null : data.getNotes().replaceAll("\u0000", ""));
        data.setTenantCode(resultMsg.getTenantId());

        String enteredBy = super.getStringValue(entity.get("enteredBy"));
        if (!StringUtils.isEmpty(enteredBy)) {
            this.usersRepository.findByIdentifierAndTenantCode(enteredBy, data.getTenantCode())
                    .blockOptional(Duration.ofSeconds(10))
                    .ifPresent(users -> data.setCwUid(users.getCwUid()));
        }


        splicLink(resultMsg, data);

       this.timeEntriesRepository
                .findByTimeentryIdAndTenantCode(resultMsg.getId(), resultMsg.getTenantId())
                .map(result -> {
                    data.setId(result.getId());
                    data.setAction("updated");
                    return data;
                })
                .defaultIfEmpty(data)
                .flatMap(this.timeEntriesRepository::save)
                .block(Duration.ofSeconds(10));

//        this.setTicketInfo(entity, timeEntry);

        this.messagingTemplate.convertAndSend("bot.task.cw", "bot.cw.timeentry", data);
    }


    private void splicLink(ResultMsg resultMsg, TimeEntry data) {
        String url = this.r2dbcEntityTemplate.select(SysDictDataEntity.class)
                .matching(Query.query(Criteria.where("tenantCode").is(resultMsg.getTenantId())
                        .and("subjectCode").is("CW")
                        .and("dictLabel").is("url")))
                .one()
                .map(SysDictDataEntity::getDictValue).block(Duration.ofSeconds(10));
        if (!ObjectUtils.isEmpty(url)) {
            String ticketUrl = "https://" + url + "/v4_6_release/ConnectWise.aspx?locale=en_US&routeTo=TimeEntryFV&recid=" + data.getTimeentryId();
            data.setLink(ticketUrl);
        }
    }


    private void setTicketInfo(JsonNode entity, TimeEntry timeentry) {
        LocalDateTime ticketUpdatedTime = super.getDateTimeValue(entity.findValue("ticketUpdatedTime"));
        if (ObjectUtils.isEmpty(ticketUpdatedTime)) {
            return;
        }
        this.ticketsRepository.findByTicketIdAndTenantCodeAndUpdatedTime(timeentry.getTicketId(),
                timeentry.getTenantCode(), ticketUpdatedTime)
                .flatMap(dbData ->
                        this.timeEntriesRepository.countTimeEntryBy(timeentry.getTenantCode(), timeentry.getTicketId(), true)
                                .map(count -> count > 0)
                                .flatMap(countFlag -> {
                                    dbData.setTimeentryResolutionFlag(countFlag);
                                    dbData.setStatusName(super.getStringValue(entity.get("ticketStatusName")));
                                    dbData.setSummary(super.getStringValue(entity.get("ticketSummary")));
                                    return this.ticketsRepository.save(dbData);
                                })
                ).subscribe();
    }

}
